SPI.c
/*
* SPI.c
* SPI Interface functions. Written for setting connection between nRF24L01 Single Chip 2.4GHz Transceiver module and MCU
* Created: 23.04.2022 13:36:45
* Author: Bohdan
*/
#include "main.h"
#include <util/delay.h> // allows usage of _delay_ms_();
#include <stdio.h> // defines sprintf();
#include "UART_avr.h"
#include "PIN_avr.h"
#include "SPI_nRF.h"
#include "SPI_nRF_Registers.h"
char pr_str[32]; // debug string
extern nRF_t nRF_module;
/*
* Setting up the SPI Interface for usage in connection between nRF Module and MCU
*/
void SPI_set(uint16_t F_Khz)
{
switch(F_Khz)
{
case 4000: // 4 MHz
{
} break;
case 1000: // 1 MHz
{
SPCR |= (1<<SPR0);
} break;
case 250: // 250 kHz
{
SPCR |= (1<<SPR1);
} break;
case 125: // 125 kHz
{
SPCR |= (1<<SPR1)|(1<<SPR0);
} break;
case 8000: // 8 MHz
{
SPSR |= (1<<SPI2X);
} break;
case 2000: // 2 MHz
{
SPSR |= (1<<SPI2X);
SPCR |= (1<<SPR0);
} break;
case 500: // 500 kHz
{
SPSR |= (1<<SPI2X);
SPCR |= (1<<SPR1);
} break;
default: break; // default value - 4 MHz frequency
}
/* Set MOSI and SCK output, all others input */
DDRB |= (1<<3)|(1<<5); // MOSI, SCK pin
/* Enable SPI, Master, set clock rate fck/16 */
//SPCR |= (1<<SPE)|(1<<DORD)|(1<<MSTR); // Bits SPI2X SPR1 SPR0 = 0; DORD = 1 - LSB is sent first
SPCR |= (1<<SPE)|(1<<MSTR); // Bits SPI2X SPR1 SPR0 = 0; DORD = 0 - MSB is sent first
}
/*
* Setting up a structure with SPI Settings for nRF (Maybe not needed?)
* Setting the SPI Interface
*/
void nRF_setup(nRF_t* nRF, rf_freq _f_kHz, rf_pwr _pwr, rf_mode _mode, pin_t _CE_pin, pin_t _CSN_pin)
{
nRF->mode = _mode;
nRF->F_Khz = _f_kHz;
nRF->PWR = _pwr;
//nRF->SS_pin = _CE_pin;
nRF->CE_pin = _CE_pin;
nRF->CSN_pin = _CSN_pin;
/* Setting up the CS and CSN Pins (Levels taken from an example) */
pin_mode(_CE_pin, OUTPUT);
pin_mode(_CSN_pin, OUTPUT);
//pin_write(_CE_pin, LOW); let it be stock mode so far (radio)
pin_write(_CSN_pin, HIGH);
SPI_set(_f_kHz);
_delay_ms(5); // wait until the radio module sets up
// Setting RF_SETUP register:
// Reading the current state of setup register (debugging)
uint8_t SETUP_REG_old = R_REGISTER(nRF, RF_SETUP_REG); // reading the status register of nRF Module
sprintf(pr_str, "Read Setup Reg: %d\n", SETUP_REG_old);
print_str(pr_str);
uint8_t SETUP_REG_new = 0;
//setting the transfer rate:
switch(_f_kHz)
{
case F_250kbps: SETUP_REG_new |= (1<<RF_DR_LOW); break;
case F_1Mbps: SETUP_REG_new |= (1<<RF_DR_HIGH); break;
case F_2Mbps: break;
}
// setting the power rate:
switch(_pwr)
{
case PWR_m18dBm: break;
case PWR_m12dBm: SETUP_REG_new |= (1<<RF_PWR_LOW); break;
case PWR_m6dBm: SETUP_REG_new |= (1<<RF_PWR_HIGH); break;
case PWR_m0dBm: SETUP_REG_new |= (1<<RF_PWR_HIGH)|(1<<RF_PWR_LOW); break;
}
sprintf(pr_str, "SETUP_REG_new = %d\n", SETUP_REG_new); // debug purposes
print_str(pr_str);
if(SETUP_REG_old != SETUP_REG_new) // Overwriting only if it is actually needed
{
sprintf(pr_str, "Writing needed\n"); // debug purposes
print_str(pr_str);
W_REGISTER(nRF, RF_SETUP_REG, SETUP_REG_new); // writing the created value of the setup register
}
sprintf(pr_str, "SETUP_REG now = %d\n", R_REGISTER(nRF, RF_SETUP_REG)); // debug purposes
print_str(pr_str);
}
/*
* A byte of informations cData is sent, after the SPIF bit set - the transmission is accomplished and the
*/
uint8_t SPI_TR_Byte(nRF_t* nRF, uint8_t cData) // Looks more like just reading of a register
{
pin_write(nRF->CSN_pin, LOW);
SPDR = cData; // Start transmission
//sprintf(pr_str, "Transferring: %d\n", cData);
//print_str(pr_str);
while(!(SPSR & (1<<SPIF))); // Wait for PREVIOUS transmission to complete
pin_write(nRF->CSN_pin, HIGH);
return(SPDR);
}
/*
*
*/
void SPI_TR_str(nRF_t* nRF, uint8_t* arr, uint8_t length)
{
pin_write(nRF->CSN_pin, LOW);
for(uint8_t i = 0; i < length; i++)
{
SPDR = arr[i]; // Start transmission
while(!(SPSR & (1<<SPIF))); // Wait for PREVIOUS transmission to complete
sprintf(pr_str, "Sent byte %d\n", arr[i]);
print_str(pr_str);
}
pin_write(nRF->CSN_pin, HIGH);
}
/************************** Functions from the Table 20, Page 51, Document "nRF24L01P_Product_Specification_1_0.pdf" **************************/
/*
*
*/
uint8_t R_REGISTER(nRF_t* nRF, uint8_t register_addr) // R_REGISTER Command from Page 51 of Document "nRF24L01P_Product_Specification_1_0.pdf"
{
// Example of information to be transferred: 0b 000A AAAA where AAAAA - Address of the Register to be red
//uint8_t send_byte = 0b11111111;
uint8_t return_byte;
return_byte = SPI_TR_Byte(nRF, register_addr);
return(return_byte);
}
/*
*
*/
void W_REGISTER(nRF_t* nRF, uint8_t register_addr, uint8_t data) // W_REGISTER Command from Page 51 of Document "nRF24L01P_Product_Specification_1_0.pdf"
{
//pin_write(nRF->CSN_pin, LOW);
//_delay_ms(1);
/******************* Weird stuff. Trying to go to the power down mode *******************
uint8_t CONFIG_OLD = R_REGISTER(nRF, CONFIG_REG);
sprintf(pr_str, "CONFIG REG = %d\n", CONFIG_OLD);
print_str(pr_str);
uint8_t go_to_PD[2];
go_to_PD[0] = CONFIG_REG | 0b00100000;
go_to_PD[1] = CONFIG_OLD &~(1<<PWR_UP);
sprintf(pr_str, "CONFIG REG NEW = %d\n", go_to_PD[1]);
print_str(pr_str);
SPI_TR_str(nRF, go_to_PD, 2);
//_delay_ms(1);
************************************************************************************************************************/
// Example of information to be transferred: 0b 001A AAAA where AAAAA - Address of the Register to be written
uint8_t comand[2]; // forming an array that will be transferred
comand[0] = 0b00100000 | register_addr;
comand[1] = data;
sprintf(pr_str, "Writing...\nByte 1: %d\nByte 2: %d\n", comand[0], comand[1]);
print_str(pr_str);
SPI_TR_str(nRF, comand, 2);
//pin_write(nRF->CSN_pin, HIGH);
}
/*
*
*/
void R_RX_PAYLOAD(nRF_t* nRF) // R_RX_PAYLOAD Command from Page 51 of Document "nRF24L01P_Product_Specification_1_0.pdf"
{
uint8_t RX_PAYLOAD_byte = 0b01100001;
SPI_TR_Byte(nRF, RX_PAYLOAD_byte);
}
/*
*
*/
void W_TX_PAYLOAD(nRF_t* nRF) // W_TX_PAYLOAD Command from Page 51 of Document "nRF24L01P_Product_Specification_1_0.pdf"
{
uint8_t WX_PAYLOAD_byte = 0b10100000;
SPI_TR_Byte(nRF, WX_PAYLOAD_byte);
}
/*
*
*/
void FLUSH_TX(nRF_t* nRF) // FLUSH_TX Command from Page 51 of Document "nRF24L01P_Product_Specification_1_0.pdf"
{
uint8_t FLUSH_TX_byte = 0b11100001;
SPI_TR_Byte(nRF, FLUSH_TX_byte);
}
/*
*
*/
void FLUSH_RX(nRF_t* nRF) // FLUSH_RX Command from Page 51 of Document "nRF24L01P_Product_Specification_1_0.pdf"
{
uint8_t FLUSH_RX_byte = 0b11100010;
SPI_TR_Byte(nRF, FLUSH_RX_byte);
}
/*
*
*/
void REUSE_TX_PL(nRF_t* nRF) // REUSE_TX_PL Command from Page 51 of Document "nRF24L01P_Product_Specification_1_0.pdf"
{
uint8_t REUSE_TX_PL_byte = 0b11100011;
SPI_TR_Byte(nRF, REUSE_TX_PL_byte);
}
/*
*
*/
void R_RX_PL_WID(nRF_t* nRF) // R_RX_PL_WID Command from Page 51 of Document "nRF24L01P_Product_Specification_1_0.pdf"
{
uint8_t R_RX_PL_WID_byte = 0b01100000;
SPI_TR_Byte(nRF, R_RX_PL_WID_byte);
}
/*
*
*/
void W_ACK_PAYLOAD(nRF_t* nRF) // W_ACK_PAYLOAD Command from Page 51 of Document "nRF24L01P_Product_Specification_1_0.pdf"
{
//uint8_t W_ACK_PAYLOAD_byte = 0b10101PPP;
//SPI_TR_Byte(nRF, W_ACK_PAYLOAD_byte);
}
/*
*
*/
void W_TX_PAYLOAD_NOACK(nRF_t* nRF) // W_TX_PAYLOAD_NOACK Command from Page 51 of Document "nRF24L01P_Product_Specification_1_0.pdf"
{
uint8_t W_TX_PAYLOAD_NOACK_byte = 0b10110000;
SPI_TR_Byte(nRF, W_TX_PAYLOAD_NOACK_byte);
}
/*
*
*/
uint8_t NOP(nRF_t* nRF) // NOP Command from Page 51 of Document "nRF24L01P_Product_Specification_1_0.pdf"
{
uint8_t NOP_byte = 0b11111111;
uint8_t return_byte;
return_byte = SPI_TR_Byte(nRF, NOP_byte);
return(return_byte);
}